﻿using System;
using System.Linq;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Automation;
using System.Text.RegularExpressions;
using Dtf.Core.Remoting;

namespace Dtf.Core
{
    public class UICollection<T> : RemotingObject, IEnumerable<T>, IEnumerator<T> where T : UIItem
    {
        public UICollection(UICollection<T> previous)
        {
            _root = previous._root;
            _scope = previous._scope;
            if (previous._filter != null)
            {
                _filter = previous._filter.Clone() as UIFilter;
            }
        }

        public UICollection(T root, UIScope scope)    //only Constructor
        {
            if (_regex_procName == null)
            {
                _regex_procName = new Regex(@"(\[(?<procName>[A-Za-z]+)\][ ]*)");
            }
            if (_regex_query == null)
            {
                _regex_query = new Regex("(?<query>[A-Za-z]+[ ]*(=|(!=)){1}[ ]*([']{1}[^']*[']{1}|[0-9]+|true)([ ]+[&||]{2}[ ]+)*)+($|(;[ ]*))");
            }

            _root = root;
            _scope = scope;

        }

        private void AddFilter(UIFilter filter)
        {
            if (_filter == null)
            {
                _filter = filter;
            }
            else
            {
                _filter.Join(filter, UIFilter.Join_Type.Join_And);
            }

        }

        /// <summary>
        /// queryString: May has [procName] spec.
        /// </summary>
        /// <param name="queryString"></param>
        /// <returns></returns>
        public T FindFirst(UIFilter queryString)
        {
            UICollection<T> items = FindAll(queryString);
            if (items.Count() > 0)
            {
                return items.ElementAt(0);
            }
            throw new UINotFoundExecption();
        }

        //public UICollection<T> FindAll(string queryString)
        //{
        //    UIFilter filter = new UIFilter(queryString);
        //    UICollection<T> uis = new UICollection<T>(this);
        //    uis.AddFilter(filter);
        //    return uis;
        //}

        //private T[] Find(string queryString, bool bFindAll)
        //{
        //    List<T> result = new List<T>();
        //    foreach (T uiItem in this)
        //    {
        //        if (_filter.IsMatch(uiItem))
        //        {
        //            result.Add(uiItem);
        //            if (!bFindAll)
        //            {
        //                break;
        //            }
        //        }
        //    }
        //    return result.ToArray();
        //}

        public UICollection<T> FindAll(UIFilter filter)
        {
            UICollection<T> newCollection = new UICollection<T>(this);
            newCollection.AddFilter(filter);
            return newCollection;
        }

        public T WaitFor(UIFilter queryString, int timeout)
        {
            T t;
            while (timeout > 0)  //will update to support AutomationStructureChange Event(finding again when event ocur);
            {
                if (TryFind(queryString, out t))
                {
                    return t;
                }
                System.Threading.Thread.Sleep(500);
                timeout -= 500;
            }
            throw new UINotFoundExecption();
        }

        public bool TryFind(UIFilter queryString, out T findItem)
        {
            UICollection<T> t = FindAll(queryString);
            if (t.Count() == 0)
            {
                findItem = null;
                return false;
            }
            findItem = t.First();
            return true;
        }


        public void Add(T item)
        {
            throw new NotSupportedException();
        }

        public bool Remove(T item)
        {
            throw new NotSupportedException();
        }

        public void Clear()
        {
            throw new NotSupportedException();
        }



        #region IEnumerable<T> Members


        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            _UIStack = new Stack<T>();
            _UIStack.Clear();
            _current = _root;//.FirstChild as T;
            return (IEnumerator<T>)this;
        }

        #endregion

        #region IEnumerable Members

        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable<T>)this).GetEnumerator();
        }

        #endregion

        #region IEnumerator<T> Members

        T System.Collections.Generic.IEnumerator<T>.Current
        {
            get
            {
                return _current;
            }
        }

        #endregion

        #region IDisposable Members

        void IDisposable.Dispose()
        {
            //throw new NotImplementedException();
        }

        #endregion

        #region IEnumerator Members

        object System.Collections.IEnumerator.Current
        {
            get
            {
                return ((System.Collections.Generic.IEnumerator<T>)this).Current;
            }
        }

        bool System.Collections.IEnumerator.MoveNext()
        {
            if (UIScope.Children == _scope)
            {
                #region Children Scope

                T next = null;
                if (_current == _root)
                {
                    next = _current.FirstChild as T;
                }
                else
                {
                    next = _current.NextSibling as T;
                }
                while (next != null && !IsMatch(next))
                {
                    next = _current.NextSibling as T;
                }
                if (next == null)
                {
                    return false;
                }
                _current = next;
                Logger4net.Logger.Instance.Info("Element name:{0}", _current.Name);

                #endregion
            }
            else if (UIScope.Descendants == _scope)
            {
                #region Descendants Scope
                {
                    T nxt = _current.FirstChild as T;
                    while (nxt != null && !IsMatch(nxt))
                    {
                        nxt = _current.FirstChild as T;
                    }
                    if (nxt != null)
                    {
                        _current = nxt;
                    }
                    else
                    {
                        nxt = _current.NextSibling as T;
                        while (nxt != null && !IsMatch(nxt))
                        {
                            nxt = _current.NextSibling as T;
                        }
                        if (nxt != null)
                        {
                            _current = nxt;
                        }
                        else    //goto parent's next node
                        {
                            nxt = _current.Parent as T;
                            while (nxt != _root)
                            {
                                T tmp = nxt.NextSibling as T;
                                if (tmp == null)
                                {
                                    nxt = nxt.Parent as T;
                                }
                            }
                            if (nxt == _root)
                            {
                                return false;
                            }
                            else
                            {
                                _current = nxt;
                            }
                        }
                    }
                }
                #endregion
            }
            return true;
        }

        void System.Collections.IEnumerator.Reset()
        {
            _current = _root;
        }

        #endregion IEnumerator Members

        private bool IsMatch(T t)
        {
            if (_filter != null)
            {
                return _filter.IsMatch(t);
            }
            return true;
        }

        public int Count
        {
            get
            {
                int count = 0;
                foreach(T t in this)
                {
                    count++;
                }
                return count;
            }
        }

        private UIFilter _filter = null;
        private T _root = null;
        private T _current = null;
        private UIScope _scope;
        private Stack<T> _UIStack;

        private static Regex _regex_query = null;
        private static Regex _regex_procName = null;

        //private List<T> _findResult = new List<T>();
    }
}
